#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <QuartzCore/QuartzCore.h>
#import <objc/runtime.h>
#import <UIKit/UIApplication.h>
#import <LockInfo/Plugin.h>

#import "FWCommon.h"
#import "FWPlugin.h"
#import "FWApplicationDelegate.h"
#import "FWApplication.h"


@implementation FWApplication

@synthesize applicationDelegate, applicationPath, preferencesPath, preferencesUpdated, pluginPreferencesPath, pluginBundle, databasePath, attributes, fwPlugin, info;


// ******************************************************************************************
#pragma mark -
#pragma mark Initialisation and object management

- (id)init
{
    if ((self = [super init])) {
        self.attributes = [NSMutableDictionary dictionaryWithCapacity:10];
        self.preferencesUpdated = [NSDate dateWithTimeIntervalSinceReferenceDate:0];
    }
    
    return self;
}

- (void)dealloc
{
    [applicationDelegate release];
    [applicationPath release];
    [preferencesPath release];
    [preferencesUpdated release];
    [pluginPreferencesPath release];
    [pluginBundle release];
    [databasePath release];
    [fwPlugin release];
    [attributes release];
    [info release];
    
    [super dealloc];
}


// ******************************************************************************************
#pragma mark -
#pragma mark Basic application control

- (BOOL)shouldUpdateForDate:(NSDate*)date
{
    // This is checked by the update method so no point repeating here
    // if (![self verifyApplication])
    //     return NO;
    
    NSTimeInterval lastUpdate = [date timeIntervalSinceReferenceDate];
    
    NSDictionary *dataAttrs = [[NSFileManager defaultManager] fileAttributesAtPath:self.databasePath traverseLink:YES];
    NSDate* dataLastMod = [dataAttrs objectForKey:NSFileModificationDate];
    if (lastUpdate < [dataLastMod timeIntervalSinceReferenceDate]) {
        XLog(@"LI:PICommon: Database updated since last refresh");
        return YES;
    }
    
    NSDictionary *pluginAttrs = [[NSFileManager defaultManager] fileAttributesAtPath:self.pluginPreferencesPath traverseLink:YES];
    NSDate* pluginLastMod = [pluginAttrs objectForKey:NSFileModificationDate];
    if (lastUpdate < [pluginLastMod timeIntervalSinceReferenceDate]) {
        XLog(@"LI:PICommon: Plugin prefs updated since last refresh");
        return YES;
    }

    // PI seems to update this a lot so let's not bother
    //
    //NSDictionary *prefsAttrs = [[NSFileManager defaultManager] fileAttributesAtPath:self.preferencesPath traverseLink:YES];
    //NSDate* prefsLastMod = [prefsAttrs objectForKey:NSFileModificationDate];
    //if (lastUpdate < [prefsLastMod timeIntervalSinceReferenceDate]) {
    //    XLog(@"LI:PICommon: Application prefs updated since last refresh");
    //    return YES;
    //}
    
    // Get time of midnight today (ie past) in UTC by building a new date from only the year, month
    // and day components of the current date.
    NSCalendar *gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
    gregorian.timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
    NSDateComponents *components = [gregorian components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
                                                fromDate:[NSDate date]];
    NSDate *midnight = [gregorian dateFromComponents:components];

    if (lastUpdate < [midnight timeIntervalSinceReferenceDate]) {
        XLog(@"LI:PICommon: Passed local midnight since last refresh");
        return YES;
    }
    
    return NO;
}

- (BOOL)verifyApplication
{
    if (![[NSFileManager defaultManager] isReadableFileAtPath:[self databasePath]]) {
        [self.applicationDelegate updateApplication:self];
        
        if (![[NSFileManager defaultManager] fileExistsAtPath:[self databasePath]]) {
            XLog(@"LI:PICommon: Failed to find database at location %@", [self databasePath]);
            return NO;
        }
    }
    
    return YES;
}

- (void)setFwPlugin:(FWPlugin *)newPlugin
{
    // Update our copy of the LockInfo plugin. Since we are never going to be garbage collected
    // the fact that we likely have a circular reference between LockInfo, FWPlugin and
    // FWApplication doesn't concern us.
    [fwPlugin release];
    fwPlugin = [newPlugin retain];
    
    lockinfo3 = [newPlugin.liPlugin respondsToSelector:@selector(launchURL:)];
    XLog(@"LI:PICommon: Detected LI3 = %i", lockinfo3);
}


// ******************************************************************************************
#pragma mark -
#pragma mark Helper functions to access LockInfo features

- (BOOL)isLockInfo3
{
    return lockinfo3;
}

- (BOOL)launchURL:(NSURL*)url
{
    if (![self isLockInfo3])
        return NO;
    
    [fwPlugin.liPlugin launchURL:url];
    return YES;
}
                
- (BOOL)launchApplicationWithIdentifier:(NSString*)identifier
{
    if (![self isLockInfo3])
        return NO;
    
    [fwPlugin.liPlugin launchApplicationWithIdentifier:identifier];
    return YES;
}


// ******************************************************************************************
#pragma mark -
#pragma mark Attribute list management

- (id)getAttribute:(NSString*)name
{
    return [self.attributes objectForKey:name];
}

- (void)setAttribute:(NSString*)name value:(NSObject*)value
{
    [self.attributes setObject:value forKey:name];
}

- (void)clearAttribute:(NSString*)name
{
    [self.attributes removeObjectForKey:name];
}

- (NSString*)resourceName
{
    if (self.fwPlugin)
        return self.fwPlugin.resourceName;
    else
        return @"FWCommon";
}

@end
